#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#include <string.h>
#include "config.h"
#include "decision.h"


/*
	decision module: decide how actionners react to the new value send by sensors
	
	fonctions to do: 
	
	+$add a rule  
	+$modify a rule
	+$delete a rule
	
	+$add a condition  
	+$delete a condition
	
	
	
	+$verify condition 
	+$verify a rule
	
	$apply rules to new value and send a reaction command to msgQ
	
	$daemon of this
	
	
*/

extern MapCapteur TabCapteur[TAILLE_TAB_CAPTEUR];



#define MSGQ_KEY_CAPTEURS 1234
#define MSGQ_KEY_ACTIONNERS 4321

void init_msgQ()
{

	// capteur update Queue init
	key_t msgkey;
	//msgkey= ftok(".",'m');
	//just a random msgkey 
	msgkey = MSGQ_KEY_CAPTEURS ;
	
	msgQCapteurUpdate = msgget(msgkey, IPC_CREAT |0666);
	//msgQCapteurUpdate = open_queue(msgkey);
	
	msgkey = MSGQ_KEY_ACTIONNERS;
	
	bal_commande_actionneur = msgget(msgkey, IPC_CREAT |0666);
	if(msgQCapteurUpdate== -1){
 		perror("Erreur creer BAL\n");
 	}

	
	
	
	
	MsgCapteur msgCU1;
	MsgCapteur msgCU2;
	int lengthMsg;
	msgCU1.type = 1;
	msgCU1.typeMessage = 2;
	strcpy(msgCU1.idCapteur,"13");
	msgCU1.valeur = 7;
	msgCU2.type = 1;
	msgCU2.typeMessage = 2;
	strcpy(msgCU2.idCapteur,"22");
	msgCU2.valeur = 9;
	lengthMsg = sizeof(MsgCapteur) - sizeof(long);
 
 	msgsnd(msgQCapteurUpdate, &msgCU1, lengthMsg,0);
	

	msgsnd(msgQCapteurUpdate, &msgCU2, lengthMsg,0);
	
	
	printf("MsgQueue initialized\n");
	
	// capteur list init
	nbCapteur = 2;
	
	MapCapteur mc;
	
	strcpy(mc.idCapteur , "13");
	mc.typeCapteur = "T";
	//mc.etat= 4;
	mc.valeur = 9.9;
	
	pTabCapteur = TabCapteur;
	
	pTabCapteur[0] =  mc;
	
	
	
	
	strcpy(mc.idCapteur , "22");
	mc.typeCapteur = "L";
	//mc.etat= 6;
	mc.valeur = 6.6;
	
	pTabCapteur[1] =  mc;
	
	printf("valeur capteur 0 %f\n",pTabCapteur[0].valeur );
	printf("valeur capteur 1 %f\n",pTabCapteur[1].valeur );
	
	printf("Capteurs initialized\n");
	
	//regle init
	
	nbRegle = 2;
	
	Condition cond;
	strcpy(cond.idCapteur ,"13");
	cond.valMin = 4;
	cond.valMax = 15;
	
	Regle regle;
	regle.tabCondition[0] = cond;
	regle.nbCondition = 1;
	strcpy(regle.idActionneur , "3");
	regle.onOff = 0;
	regle.valeur = 0.3;
	
	TabRegle[0] = regle;
	
	strcpy(cond.idCapteur , "22");
	cond.valMin = 5;
	cond.valMax = 30;
	
	regle.tabCondition[0] = cond;
	regle.nbCondition = 1;
	strcpy(regle.idActionneur, "4");
	regle.onOff = 1;
	regle.valeur = 0.5;
	
	TabRegle[1] = regle;
	
	printf("regles initialized\n");

	
	
}

int addCondition(int regleIndex, Condition cond){
	if(TabRegle[regleIndex].nbCondition+1<MAX_COND){
		
		//TabRegle[regleIndex].nbCondition++;
		//TabRegle[regleIndex].tabCondition[nbCondition] = cond;
		Regle * rgl=& TabRegle[regleIndex];
		rgl->tabCondition[rgl->nbCondition]= cond;
		rgl->nbCondition++;
		printf("condition %d ajoute :)   \n",rgl->nbCondition);
		
		return OK;
	}else{
		printf("Trop de condition pour un regle\n");
		return -1;
	}
	
}

int deleteCondition(int regleIndex,int condIndex){
	
	if((regleIndex<nbRegle)&&(regleIndex>=0)){
		
		Regle * rgl=& TabRegle[regleIndex];
		
		if((rgl->nbCondition > condIndex)&&(condIndex>=0)){
			rgl->tabCondition[condIndex]=rgl->tabCondition[rgl->nbCondition-1];
			rgl->nbCondition--;
			printf("condition %d supprime :)   \n",condIndex);
		}
		return OK;
	}else{
		printf("indice invalid\n");
		return -1;
	}
	return OK;
}

int getCapteurTabIndex(char * capteurId){
	int i = 0 ;
	while(i<nbCapteur){
		if(strcmp(pTabCapteur[i].idCapteur,capteurId)==0)
			return i;
		i++;
	
	}
	return -1;
}

int conditionOK(int regleIndex,int condIndex){

	//debug TODO
			//printf("#######DEBUG2 : HERE nbRegle %d\n",nbRegle);
	if((regleIndex<nbRegle)&&(regleIndex>=0)){
		
		Regle * rgl= &(pTabRegle[regleIndex]);
		

		if((rgl->nbCondition > condIndex)&&(condIndex>=0)){
			Condition cond = rgl->tabCondition[condIndex];
			//printf("regle %d condition %d  capteur %s:   \n",regleIndex,condIndex,cond.idCapteur );
			//printf("min %f max %f value %f  \n",cond.valMin,cond.valMax,pTabCapteur[getCapteurTabIndex(cond.idCapteur)].valeur );
			//debug TODO
			//printf("#######DEBUG3 : cond.idCa %s\n",cond.idCapteur);
			if((pTabCapteur[getCapteurTabIndex(cond.idCapteur)].valeur<=cond.valMax)&&
			(pTabCapteur[getCapteurTabIndex(cond.idCapteur)].valeur>=cond.valMin)){
				printf("regle %d condition %d OK :)   \n",regleIndex,condIndex);
				return 1;
			}
			
		}
		return 0;
	}else{
		printf("indice invalid\n");
		return 0;
	}
	return 0;

}

int activeRegle(int regleIndex){
	
	int i = 0 ; 
	Regle * rgl=pTabRegle;
	//debug
	//printf("DEBUG7########################nbCond %d\n",((Regle *)pTabRegle)[0].nbCondition);
	//printf("DEBUG6########################nbCond %d\n",((Regle *)pTabRegle)[1].nbCondition);

	while ( i < ((Regle *)pTabRegle)[regleIndex].nbCondition  ) {
		printf(" OK = %d \n", conditionOK(regleIndex,i) );
		if(conditionOK(regleIndex,i)!=1){
			//printf(" ");
			printf("Regle %d non active for condition %d \n", regleIndex,i);
			return 0 ;
		}
		i++;
	}
	
	
	printf("Regle %d active :)\n", regleIndex);
	
	//need msg format here and send it to actionner
	
	MsgActionneur msgA;
	msgA.type = 1;
	strcpy(msgA.idActionneur,rgl[regleIndex].idActionneur);
	msgA.onOff = rgl[regleIndex].onOff;
	msgA.valeur = rgl[regleIndex].valeur;
	
	
	printf("actionner %s passe a l'etat %d valeur %f\n",rgl[regleIndex].idActionneur, rgl[regleIndex].onOff ,rgl[regleIndex].valeur);
	
	//refresh the actionner table
	if (msgsnd(bal_commande_actionneur,(void *)&msgA,sizeof(MsgActionneur)-sizeof(long),IPC_NOWAIT) < 0 )
	{
		perror ("msgsnd error");
	}
	else
		printf("TRegle :message sent to bal_commande_actionneur\n");
	
	
	
	return 1;
}



//test all rules
int decide(){

	int i = 0;

	while (i<nbRegle) {
		activeRegle(i);
		
		i++;
	}
	
	return OK;
}



int addRule(Regle *regle){
	if(nbRegle+1<NB_MAX_REGLE){
		TabRegle[nbRegle] = *regle;
		printf("regle %d ajoute :)   \n",nbRegle);
		nbRegle++;
		
		return OK;
	}else {
		return -1;
		printf("Trop de regles :(  \n");
	}
	
}

int ModifyRule(Regle *regle, int index){

	TabRegle[index] = *regle;
	if(nbRegle<NB_MAX_REGLE){
		TabRegle[index] = *regle;
		printf("regle %d modifie :)   \n",index);
		return OK;
	}else {
		printf("indice invalid\n");
		return -1;
	}
	
}

int getRuleIndex(const Regle *regle ){

	int i = 0;
	while(i < NB_MAX_REGLE){
		if(&TabRegle[i]==regle){
			return i;
		}
		
		i++;
		
	}
	return -1;
}

int DeleteRule(int index){
	
	if(index >= nbRegle){
		printf("index %d invalid :(  \n",index);
	}
	
	nbRegle-- ;
	
	
	TabRegle[index] = TabRegle[nbRegle];
	printf("regle %d supprime :)   \n",index);
	
	
	return OK;
}

/* Daemon here !!!*/
int updateTabCapteur(){
	
	int run = 1;
	
	
	while (run==1) {
		MsgCapteur msg;
		int lengthMsg = sizeof(MsgCapteur) - sizeof(long);
		long type = 1;
		
		if(msgrcv(msgQCapteurUpdate, &msg, lengthMsg,type,MSG_NOERROR)==-1){
			perror("msgrcv error\n");
		}else{
			
			if (msg.typeMessage ==1 ) {
				//show error msg
				printf("erreur de capteur : %s \n",msg.idCapteur);
			}
			else if(msg.typeMessage ==4){
				//stop daemon
				run = 0;
				printf("Daemon updateTabCapteur terminee\n");
			}
			else{
				//normal fonction
				printf("msg: idCapteur %s  valeur %f\n", msg.idCapteur,msg.valeur);
				
				if (getCapteurTabIndex(msg.idCapteur)>=0) {
					printf("tableau mise a jour\n");
					pTabCapteur[getCapteurTabIndex(msg.idCapteur)].valeur = msg.valeur;
				}else {
					printf("idCapteur invalid\n");
				}

				decide();
				
			}
		}
		
		
		//test only
		run =0;
		
		
		
		
	}
	
	
	
	
	return 1;
}


void testMsgQ(){
	
	
	MsgCapteur msg;
	int lengthMsg = sizeof(MsgCapteur) - sizeof(long);
	long type = 1;
	printf("lololololol\n");
	if(msgrcv(msgQCapteurUpdate, &msg, lengthMsg,type,MSG_NOERROR)==-1){
		perror("msgrcv error\n");
	}else{
	
		printf("msg: %s\n", msg.idCapteur);
	}
	printf("lalala\n");
}

void testCondition(){
	Condition cond;
	strcpy(cond.idCapteur , "13");
	cond.valMin = 0;
	cond.valMax = 100;
	addCondition(0,cond);
	
	if(conditionOK(0,0)){
		printf("regle 0 condition 0 valid \n");}
	else{
		printf("regle 0 condition 0 invalid \n");
	}
	deleteCondition(0,0);
	
}

void testRegle(){
	
	printf("Verifier regle 0 \n");
	
	if (activeRegle(0)){
		printf("Regle 0 active \n");
	}
	else{
		printf("Regle 0 non active \n");
	}

}

/*
int main(int argc, const char* argv[] )
{
	init_msgQ();
	testMsgQ();
	updateTabCapteur();
	//();
	//testCondition();
	//testRegle();
	
	return 0;
}
*/

